﻿JMacroDB={}
JMacroNameDB={}
JMacroItemDB={}
JMacroSpellDB={}
JMacroLinkCache={}
JMacroBag={}
JMacroSpells={}
JMacroBagCount={}
JTYPE_BATTLE=1 --战斗
JTYPE_PROTECT=2 --守护 
JTYPE_BUFF=4 --BUFF
JTYPE_HP=8 --血
JTYPE_MP=16 --魔
JTYPE_FOOD=32 --食物
JTYPE_DRINK=64
--药水，药剂，食物和饮料
--HPS 每秒生命,MPS 每秒魔法，命，魔，力，敏，智，耐，防，冰抗，火抗，奥抗，暗抗，自然抗，近攻，远攻，法，疗，近攻爆，远攻爆，法爆，疗爆
--20 代表 20 点， <0 时 0.1000 ,代表 1000%, 0.0005 代表 5%
local ID,JTYPE,MINLEVEL,LEVEL,COOLDOWN,CHANNELTIME,DURATION = 1,2,3,4,5,6,7
local HPS,MPS,HP,MP,MAXHP,MAXMP,STR,DEX,ITEL,VIL,SPR = 8,9,10,11,12,13,14,15,16,17,18
local CLOSEATTACK,RANGEATTACK,SPELL,HEAL = 19,20,21,22
local CLOSEATTACKCRIT,RANGEATTACKCRIT,SPELLCRIT,HEALCRIT= 23,24,25,26
local MAGICMADE=27
local L=JMacroLocale
local revers={}

if table.getn == nil then
	local fun, err = loadstring("return function(tb) return #tb end")
	table.getn = fun()
end 

local getn=table.getn

if strfind == nil then strfind=string.find end
if strsplit == nil then strsplit=function(sep,str) return str end end


function JMacroScanBag()
	JMacroOldBag = JMacroBag
	JMacroBag={}
	JMacroBagCount={}
	local item
	for bag=0,4 do
		local num = GetContainerNumSlots(bag) 
		for slot = 1,num do
			item =GetJMacroItem(bag,slot);
			local _, count, _, _, _ = GetContainerItemInfo(bag, slot)
			if(item~=nil and item.name~=nil)then
				if(JMacroBagCount[item.name]~=nil)then
					JMacroBagCount[item.name]=JMacroBagCount[item.name]+count
				else
					JMacroBagCount[item.name]= count
				end
				--print(item.name.." 发现 "..item.total)
				JMacroBag[item.name]=item
			end
		end
	end
end

local function StartWith(str,sub)
	local begin,_=string.find(str,sub)
	return begin==1
end

--20点  20, 2% 0.0002
local function GetPointValue(str,def)
	local _,_,k=strfind(str,L["pattern.percent"])
	if(k)then return tonumber(k)/10000 end
	_,_,k = strfind(str,L["pattern.point"])
	if(k)then return tonumber(k) end
	_,_,k = strfind(str,"(%d+)")
	if(k)then return tonumber(k) end
	return def
end

--20到50点魔法 ，20，50， 2%到3% , 0.0002,0.0003
local function GetMinMax(str,def)
	local _,_,s1,s2= strfind(str,L["pattern.minToMax"])
	if(s1 and s2 ) then
		local v1,v2= GetPointValue(s1,def),GetPointValue(s2,def)
		return math.min(v1,v2),math.max(v1,v2)
	else
	    local v= GetPointValue(str,def)
	    return v,v
	end
end

-- return (min+max)/2
local function GetAvgValue(str,def)
	local min,max = GetMinMax(str,def)
	if(min and max)then
	    return (min+max)/2
	else
	    return def
	end
end

--20分钟 转换为 1200
local function TimeToSeconds(str)
	local _,_,k=strfind(str,L["pattern.hours"])
	if(k)then return 3600*tonumber(k) end
	_,_,k = strfind(str,L["pattern.minutes"])
	if(k)then return 60*tonumber(k) end
	_,_,k = strfind(str,L["pattern.seconds"])
	if(k)then return tonumber(k) end
	return nil
end

local function GetSeconds(str,pattern,def)
	local _,_,t=strfind(str,pattern)
	if(t==nil)then return nil end
	return TimeToSeconds(t) or def
end

local function AddAttribIfMatch(str,pattern,attrs,key)
	if(strfind(str,pattern))then
		attrs[getn(attrs)+1]=key
	end
end

--生命和法力，治疗效果和法术伤害
local function GetAttribKeys(str)
	local attrs = {}
	AddAttribIfMatch(str,L["health"],attrs,MAXHP)
	AddAttribIfMatch(str,L["mana"],attrs,MAXMP)
	if(strfind(str,L["allattr"]))then
		attrs[getn(attrs)+1]=STR
		attrs[getn(attrs)+1]=DEX
		attrs[getn(attrs)+1]=VIL
		attrs[getn(attrs)+1]=ITEL
		attrs[getn(attrs)+1]=SPR
	else
		AddAttribIfMatch(str,L["str"],attrs,STR)
		AddAttribIfMatch(str,L["dex"],attrs,DEX)
		AddAttribIfMatch(str,L["itel"],attrs,ITEL)
		AddAttribIfMatch(str,L["vil"],attrs,VIL)
		AddAttribIfMatch(str,L["spr"],attrs,SPR)
	end
	if(strfind(str,L["attack.range"]))then
		attrs[getn(attrs)+1]=RANGEATTACK
	elseif(strfind(str,L["attack.close"]))then
		attrs[getn(attrs)+1]=CLOSEATTACK
	elseif(strfind(str,L["attack"]))then
		attrs[getn(attrs)+1]=RANGEATTACK
		attrs[getn(attrs)+1]=CLOSEATTACK
	end
	if(strfind(str,L["spell & heal"]) or strfind(str,L["spell & heal 2"]) )then
		attrs[getn(attrs)+1]=SPELL
		attrs[getn(attrs)+1]=HEAL
	elseif(strfind(str,L["spell"]))then
		attrs[getn(attrs)+1]=SPELL
	elseif(strfind(str,L["heal"]))then
		attrs[getn(attrs)+1]=HEAL
	end
	if(strfind(str,L["crit.range"]))then
		attrs[getn(attrs)+1]=RANGEATTACKCRIT
	elseif(strfind(str,L["crit.close"]))then
		attrs[getn(attrs)+1]=CLOSEATTACKCRIT
	elseif(strfind(str,L["crit.attack"]))then
		attrs[getn(attrs)+1]=RANGEATTACKCRIT
		attrs[getn(attrs)+1]=CLOSEATTACKCRIT
	end
	if(strfind(str,L["crit.spell"]))then
		attrs[getn(attrs)+1]=SPELLCRIT
	elseif(strfind(str,L["crit.heal"]))then
		attrs[getn(attrs)+1]=HEALCRIT
	end
	return attrs
end

--GuessEffects, save to eff
local function JGetEffects(tip,eff)
	if(eff==nil)then return nil end
	if(string.find(tip,L["pattern.magicmade"]))then eff[MAGICMADE]=1 end
	local b,e,info=string.find(tip,L["pattern.use"])
	if(b==nil)then return nil end
	eff.jtype = eff.jtype or 0
	--local words={strsplit(L["pattern.sep"],info)}
	local w,k,v,num,t,keys,i,j,nextWord

	_,_,w,nextWord=string.find(tip,L["pattern.sep"])
	while(w) do
		--动词检验
		_,_,k,v = strfind(w,L["pattern.heal"])
		--恢复
		if(k or v)then
			local num = GetAvgValue(v,0)
			local channel = GetSeconds(k,L["pattern.channel"])
			local t = GetSeconds(w,L["pattern.bufftime"])
			local keys = GetAttribKeys(v)
			if(channel == nil or channel==0 )then channel = 1 end
			for j=1,getn(keys) do
				if(keys[j]==MAXHP)then 
					keys[j]=HPS
				elseif(keys[j]==MAXMP)then
					keys[j]=MPS
				end
				eff[keys[j]]= num/channel
			end
			eff[CHANNELTIME]=eff[CHANNELTIME] or channel
			eff[DURATION]=eff[DURATION] or t
		else
			_,_,k,v=strfind(w,L["pattern.enhance"])
			--提高
			if(k)then
				num = GetAvgValue(v,0)
				t = GetSeconds(w,L["pattern.bufftime"])
				keys = GetAttribKeys(k)
				for j=1,getn(keys) do
					eff[keys[j]]= num
				end
				if(t)then eff[DURATION]=t end
			end
		end
		
		if(string.find(w,L["pattern.battle"]))then eff.jtype=bit.bor(eff.jtype,JTYPE_BATTLE); end
		if(string.find(w,L["pattern.protect"]))then eff.jtype=bit.bor(eff.jtype,JTYPE_PROTECT); end
		if(string.find(w,L["pattern.food"]))then eff.jtype=bit.bor(eff.jtype,JTYPE_FOOD); end
		t = GetSeconds(w,L["pattern.cooldown"]) or GetSeconds(w,L["pattern.spellcooldown"])
		if(t)then 
			eff.cooldown=t
		end
		if(string.find(w,L["pattern.newquest"]))then eff.newquest= true end
		if(nextWord)then 
			_,_,w,nextWord=string.find(nextWord,L["pattern.sep"])
		else
			w=nil
		end
	end
	
	return eff
end

function IsJType(type,jt)
	return bit.band(type,jt)~=0
end

local function JGuessTip(item,tip)
	item.eff = item.eff or {}
	JGetEffects(tip,item.eff)
	if(item.subType==L["subtypes"][1]) then
		--食物与饮料
		
	elseif(item.type==L["subtypes"][2])then
		--药水
		
	elseif(item.type==L["subtypes"][3]) then --药剂

	elseif(item.subType==L["subtypes"][1]) then
	
	end
end

local function JGetItemTooltips(bag, slot)
	local lnk = GetContainerItemLink(bag, slot);
	if not lnk then
		return nil;
	end
	local ret={}
	-- scan tooltip text lines 2-6 to find "openable-tag"
	JMacroTempTooltip:ClearLines();
	JMacroTempTooltip:SetBagItem(bag, slot);
	local i=0;
	for i = 1, 10 do
		local field = getglobal("JMacroTempTooltipTextLeft"..i);
		if field then
			ret[i]=field:GetText()
		else 
			break
		end
	end
	c = #ret
	for j = 1, 10 do
		local field = getglobal("JMacroTempTooltipTextRight"..j);
		if field then
			if(field:GetText())then
				c=c+1
				ret[c]=field:GetText()
			end
		else
			break
		end
	end

	return ret;
end

function GetJMacroItem(bag,slot)
	local link = GetContainerItemLink(bag,slot) 
	--if((not IsUsableItem(link)) or IsEquippableItem(link))then return nil end
	--if(not IsConsumableItem(link)) then return nil end
	
	if(link == nil)then return nil end
	local item = JMacroLinkCache[link]
	if(item ~= nil) then return item  end
	
	local _,itemId,enhanceId=JMacro_GetItemIDs(link)
	item = JMacroItemDB[itemId]
	if(item ~= nil and item.name~=nil) then return item  end
	
	item = {}
	item.name, item.link, item.rarity, 
	item.level, item.minLevel, item.type, item.subType, item.maxStack,
	item.equipLoc, item.texture = GetItemInfo(link) 

	local tips=JGetItemTooltips(bag,slot) or {}

	for i=1,getn(tips) do
		--JMacroDebug(item.name,i,tips[i])
		JGuessTip(item,tips[i])
	end
	item.tips=tips
	item.id=itemId
	JMacroItemDB[itemId]=item
	JMacroLinkCache[link]=item
	
	if(item.name ~= nil)then
		JMacroNameDB[item.name]=item
	end
end

local function JGetSpellTooltips(spellIndex,booktype)
	local lnk = GetSpellLink(spellIndex,booktype);
	if not lnk then
		return nil;
	end
	local ret={}
	-- scan tooltip text lines 2-6 to find "openable-tag"
	JMacroTempTooltip:ClearLines();
	--JMacroTempTooltip:SetSpellByID(spellId);
	JMacroTempTooltip:SetSpell(spellIndex,booktype) 
	local i=0;
	for i = 1, 10 do
		local field = getglobal("JMacroTempTooltipTextLeft"..i);
		if field then
			ret[i]=field:GetText()
		else
			break
		end
	end
	local c = #ret
	for j = 1, 10 do
		local field = getglobal("JMacroTempTooltipTextRight"..j);
		if field then
			if(field:GetText())then
				c=c+1
				ret[c]=field:GetText()
			end
		else 
			break
		end
	end

	return ret;
end

function GetJMacroSpell(spellIndex,booktype)
	local link = GetSpellLink(spellIndex,booktype)
	if(link == nil)then return nil end
	local spell = JMacroLinkCache[link]
	if(spell ~= nil) then return spell  end
	
	local t,spellId=JMacro_GetItemIDs(link)
	spell = JMacroSpellDB[spellId]
	if(spell ~= nil and spell.name~=nil) then return spell  end
	spell = {}
	spell.name, spell.rank, spell.icon, spell.powerCost, spell.isFunnel, spell.powerType, spell.castingTime, spell.minRange, spell.maxRange = GetSpellInfo(spellId)
	local tips=JGetSpellTooltips(spellIndex,booktype) or {}
	for i=1,getn(tips) do
		JGuessTip(spell,tips[i])
	end
	spell.tips=tips
	spell.id=spellId
	JMacroSpellDB[spellId]=spell
	JMacroLinkCache[link]=spell
	
	if(spell.name ~= nil)then
		JMacroNameDB[spell.name]=spell
	end
end

function JMacroScanSpellbook()
	JMacroSpells={}
	-- print a list of harmful spells
	local numTabs = GetNumSpellTabs()
	for i=1,numTabs do
	  local name,texture,offset,numSpells = GetSpellTabInfo(i)
	  for spellId=1,numSpells do
		local si = offset + spellId
		local jspell = GetJMacroSpell(si,'player')
		if(jspell~=nil)then
			JMacroSpells[jspell.name] = jspell
		end
	  end
	end

end

--WoW 3.0 supported
--return type, itemid, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId 
function JMacro_GetItemIDs(itemlink)
	local item = JMacroLinkCache[itemlink]
	if(item ~= nil)then return item.id end
	if (strfind(itemlink,":") == nil) then
		JMacroDebug(itemlink.." error");
		return;
	end

	local justItemId = string.gsub(itemlink,".-\124H([^\124]*)\124h.*", "%1");
	--return type, itemid, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId = strsplit(":",justItemId);
	return strsplit(":",justItemId);
end

--== Universal Functions ==--
-- The Error input is for error message overrides. Any input to Error will suppress error message output.

-- mode 0 = base item ID, anything else = Full item ID
function ItemID_GetItemID_REF(itemlink,mode,error)
	if (strfind(itemlink,":") == nil) then
		if (error == nil) then
			ItemID_Msg(ITEMID_IDINVALID,"Error");
		end
		return;
	end

	local justItemId = string.gsub(itemlink,".-\124H([^\124]*)\124h.*", "%1");
	local type, itemid, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId = strsplit(":",justItemId);

	if (mode == 0) then
		finallink = itemid;
	else
		if uniqueId ~= nil then
			finallink = strjoin(":",type, itemid, enchantId, jewelId1, jewelId2, jewelId3, jewelId4, suffixId, uniqueId);
		else
			finallink = itemid;
		end
	end

	-- EnchantID is added at the end, cause it is use by QuestIDs to determine Quest Levels.
	return tostring(gsub(finallink, "\124", "\124\124")), type, enchantId;
end


if(L==nil)then
--Simple Test Codes
L={
	["types"]={"消耗品"},
	["subtypes"]={"食物和饮料","药水","药剂","合剂","绷带","物品强化","卷轴","其它","坐骑","饰品"},
	
	["pattern.battle"]="战斗药剂",
	["pattern.protect"]="守护药剂",
	["pattern.use"]="使用：(.+)",
	["pattern.sep"]="(.-)。(.*)",
	["pattern.channel"]="(%d+.+)内",
	["pattern.cooldown"]="%((%d+.+)冷却%)",
	["pattern.heal"]="(.-)恢复(.+)",
	["pattern.enhance"]="使(.+)提高(%d+.+)",
	["pattern.persecond"]="每(%d)秒",
	["pattern.bufftime"]="持续(%d+.+)",
	["pattern.hours"]="(%d+)小时",
	["pattern.minutes"]="(%d+)分钟",
	["pattern.seconds"]="(%d+)秒",
	["pattern.minToMax"]="(%d+.-)到(%d+.-)",
	["pattern.food"]="必须保持坐姿",
	["pattern.point"]="(%d+)点",
	["pattern.percent"]="(%d+)%%",
	
	["health"]="生命",
	["mana"]="法力",
	["str"]="力量",
	["dex"]="敏捷",
	["itel"]="智力",
	["vil"]="耐力",
	["spr"]="精神",
	["allattr"]="所有属性",
	["attack"]="攻击强度",
	["attack.close"]="近身攻击强度",
	["attack.range"]="远程攻击强度",
	["spell & heal"]="法术和治疗效果",
	["spell & heal 2"]="治疗和法术效果",
	["spell"]="法术效果",
	["heal"]="治疗效果",
	["crit.attack"]="爆击几率",
	["crit.close"]="近身攻击爆击几率",
	["crit.range"]="远程攻击爆击几率",
	["crit.spell"]="法术致命等级",
	["crit.heal"]="治疗爆击几率",
}
print(GetSeconds("持续20分钟","持续(%d+.+)")) 
print(GetPointValue("20点"))
print(GetPointValue("20%"))
print(GetPointValue("20")) 
local att = GetAttribKeys("力量敏捷和远程攻击强度")
print(table.concat(att,","))
local item={}
--JGuessTip(item,"使用：使远程攻击强度提高20到30点，持续1小时。")
JGuessTip(item,"使用：30秒内恢复7500生命。")
--进食时需要保持坐下。如果你花至少10秒进食，你将获得进食充分效果，并得到20点命中等级和20点精神，持续30分钟。
if(item.eff)then
	for k,v in pairs(item.eff) do
		print(k)
		print(v)
	end
end

end